package cn.caplike.demo.nio._2021.selector.another_demo;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Description: 客户端.
 *
 * @author LiKe
 * @version 1.0.0
 * @date 2022-01-25 13:20
 */
public class NioClient {

    @SuppressWarnings("InfiniteLoopStatement")
    public static void main(String[] args) {
        try {
            final SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);

            final Selector selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_CONNECT); // 客户端向服务端发起连接
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 8899));

            while (true) {
                selector.select(); // 阻塞, 表示服务端没有向客户端返回任何事务
                final Set<SelectionKey> selectionKeys = selector.selectedKeys();

                for (final SelectionKey selectionKey : selectionKeys) {
                    if (selectionKey.isConnectable()) {
                        // 与服务端已经建立好了连接
                        // 获取与服务端建立好连接的 SocketChannel 对象
                        final SocketChannel client = (SocketChannel) selectionKey.channel();

                        if (client.isConnectionPending()) {
                            client.finishConnect(); // 连接真正建立

                            final ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
                            writeBuffer.put((LocalDateTime.now() + " 连接成功").getBytes());

                            writeBuffer.flip();
                            client.write(writeBuffer);

                            ExecutorService executorService = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
                            executorService.submit(() -> {
                                while (true) {
                                    try {
                                        writeBuffer.clear();
                                        InputStreamReader inputStreamReader = new InputStreamReader(System.in);
                                        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

                                        final String sendMessage = bufferedReader.readLine();

                                        writeBuffer.put(sendMessage.getBytes());
                                        writeBuffer.flip();

                                        client.write(writeBuffer);
                                        // @formatter:off
                                    } catch (Exception any) { any.printStackTrace(); }
                                }
                            });
                        }

                        // ~ 注册(服务端向客户端发送数据的)读取事件
                        client.register(selector, SelectionKey.OP_READ);
                    } else if (selectionKey.isReadable()) {
                        SocketChannel client = (SocketChannel) selectionKey.channel();

                        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                        int count = client.read(readBuffer);
                        if (count > 0) {
                            String receivedMessage = new String(readBuffer.array(), 0, count);
                            System.out.println("received: " + receivedMessage);
                        }
                    } else System.err.println("Unreachable event: " + selectionKey);
                }

                selectionKeys.clear(); // !
            }
        } catch (Exception ex) { ex.printStackTrace(); }
    }
}
